/*********************************************************************
 *** 名称 ：GameCore.cpp
 *** 描述 ：GameCore类中所声明的方法的实现。
 *********************************************************************/
#include "GameCore.h"

GameCore::GameCore()
{
    this->myGameGUI = new GameGUI();
    this->myAudioPlayer = new GameAudio();
    this->level = 1;
    this->levelName = "";
    for(int i = 0; i < 5; i++) {
        for(int j = 0; j < 4; j++) {
            this->currentMap[i][j] = -1;
        }
    }
    this->steps = 0;
    this->closeSound = false;
}

GameCore::~GameCore()
{

}

void GameCore::loadMapFromFile(int playLevel)
{
    ifstream in("data/map.dat");

    char tmp;
    int i = 0;
    while(i<playLevel) {
        in>>tmp;
        if(tmp == '#') i++;
    }
    in>>tmp;
    while(tmp != '@') {
        this->levelName += tmp;
        in>>tmp;
    }

    int xStart, yStart, kind;

    /* 悲剧，小曹还得先独自来 */
    in>>xStart>>yStart>>kind;
    RoleInfo king(xStart, yStart, kind);
    rolesInfo.push_back(king);
    this->currentMap[yStart][xStart] = 0;
    this->currentMap[yStart][xStart + 1] = 0;
    this->currentMap[yStart + 1][xStart] = 0;
    this->currentMap[yStart + 1][xStart + 1] = 0;
    /* 接着五虎猛将上 */
    for( i = 1; i < 6; i++) {
        in>>xStart>>yStart>>kind;
        RoleInfo general(xStart, yStart, kind);
        rolesInfo.push_back(general);
        this->currentMap[yStart][xStart] = i;
        if(kind == GameSystem::ROLE_CARD_X) {
            this->currentMap[yStart][xStart + 1] = i;
        } else {
            this->currentMap[yStart + 1][xStart] = i;
        }
    }
    /* 还有四个抢劫的 */
    for( i = 6; i < 10; i++) {
        in>>xStart>>yStart>>kind;
        RoleInfo soldier(xStart, yStart, kind);
        rolesInfo.push_back(soldier);
        this->currentMap[yStart][xStart] = i;
    }

    in.close();
}

int GameCore::isThereARole(int &x, int &y)
{
    x = (x - GameSystem::FIELD_LEFT) / GameSystem::UNIT_WIDTH;
    y = (y - GameSystem::FIELD_TOP) / GameSystem::UNIT_WIDTH;
    return this->currentMap[y][x];
}

void GameCore::controlMovement(int &role, int x, int y)
{
    int xStart, yStart, kind;
    xStart = this->rolesInfo[role].getRoleInfoX();
    yStart = this->rolesInfo[role].getRoleInfoY();
    kind   = this->rolesInfo[role].getRoleInfoK();

    int direct;
    if(yStart > y) {
        direct = 0;
    } else if(xStart > x) {
        direct = 1;
    } else if(xStart + 2 - kind <= x) {
        direct = 2;
    } else {
        direct = 3;
    }

    switch(role) {
    case 0:
        switch(direct) {
        case 0:
            if((this->currentMap[yStart - 1][xStart] == -1)	&& (this->currentMap[yStart - 1][xStart + 1] == -1)) {
                this->currentMap[yStart - 1][xStart] = 0;
                this->currentMap[yStart - 1][xStart + 1] = 0;
                this->currentMap[yStart + 1][xStart] = -1;
                this->currentMap[yStart + 1][xStart + 1] = -1;
                this->rolesInfo[0].setRoleInfoY(yStart - 1);
            } else {
                role = -1;
            }
            break;
        case 1:
            if((this->currentMap[yStart][xStart - 1] == -1)	&& (this->currentMap[yStart + 1][xStart - 1] == -1)) {
                this->currentMap[yStart][xStart - 1] = 0;
                this->currentMap[yStart + 1][xStart - 1] = 0;
                this->currentMap[yStart][xStart + 1] = -1;
                this->currentMap[yStart + 1][xStart + 1] = -1;
                this->rolesInfo[0].setRoleInfoX(xStart - 1);
            } else {
                role = -1;
            }
            break;
        case 2:
            if((this->currentMap[yStart][xStart + 2] == -1)	&& (this->currentMap[yStart + 1][xStart + 2] == -1)) {
                this->currentMap[yStart][xStart + 2] = 0;
                this->currentMap[yStart + 1][xStart + 2] = 0;
                this->currentMap[yStart][xStart] = -1;
                this->currentMap[yStart + 1][xStart] = -1;
                this->rolesInfo[0].setRoleInfoX(xStart + 1);
            } else {
                role = -1;
            }
            break;
        case 3:
            if((this->currentMap[yStart + 2][xStart] == -1)	&& (this->currentMap[yStart + 2][xStart + 1] == -1)) {
                this->currentMap[yStart + 2][xStart] = 0;
                this->currentMap[yStart + 2][xStart + 1] = 0;
                this->currentMap[yStart][xStart] = -1;
                this->currentMap[yStart][xStart + 1] = -1;
                this->rolesInfo[0].setRoleInfoY(yStart + 1);
            } else {
                role = -1;
            }
            break;
        }
        break;
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        switch(direct) {
        case 0:
            if((this->currentMap[yStart - 1][xStart] == -1)	&& (this->currentMap[yStart - 1][xStart + 1 - kind] == -1)) {
                this->currentMap[yStart - 1][xStart] = role;
                this->currentMap[yStart - 1][xStart + 1 - kind] = role;
                this->currentMap[yStart + kind][xStart] = -1;
                this->currentMap[yStart + kind][xStart + 1 - kind] = -1;
                this->rolesInfo[role].setRoleInfoY(yStart - 1);
            } else {
                role = -1;
            }
            break;
        case 1:
            if((this->currentMap[yStart][xStart - 1] == -1)	&& (this->currentMap[yStart + kind][xStart - 1] == -1)) {
                this->currentMap[yStart][xStart - 1] = role;
                this->currentMap[yStart + kind][xStart - 1] = role;
                this->currentMap[yStart][xStart + 1 - kind] = -1;
                this->currentMap[yStart + kind][xStart + 1 - kind] = -1;
                this->rolesInfo[role].setRoleInfoX(xStart - 1);
            } else {
                role = -1;
            }
            break;
        case 2:
            if((this->currentMap[yStart][xStart + 2 - kind] == -1)	&& (this->currentMap[yStart + kind][xStart + 2 - kind] == -1)) {
                this->currentMap[yStart][xStart + 2 - kind] = role;
                this->currentMap[yStart + kind][xStart + 2 - kind] = role;
                this->currentMap[yStart][xStart] = -1;
                this->currentMap[yStart + kind][xStart] = -1;
                this->rolesInfo[role].setRoleInfoX(xStart + 1);
            } else {
                role = -1;
            }
            break;
        case 3:
            if((this->currentMap[yStart + 1 + kind][xStart] == -1)	&& (this->currentMap[yStart + 1 + kind][xStart + 1 - kind] == -1)) {
                this->currentMap[yStart + 1 + kind][xStart] = role;
                this->currentMap[yStart + 1 + kind][xStart + 1 - kind] = role;
                this->currentMap[yStart][xStart] = -1;
                this->currentMap[yStart][xStart + 1 - kind] = -1;
                this->rolesInfo[role].setRoleInfoY(yStart + 1);
            } else {
                role = -1;
            }
            break;
        }
        break;
    case 6:
    case 7:
    case 8:
    case 9:
        switch(direct) {
        case 0:
            if(this->currentMap[yStart - 1][xStart] == -1) {
                this->currentMap[yStart - 1][xStart] = role;
                this->currentMap[yStart][xStart] = -1;
                this->rolesInfo[role].setRoleInfoY(yStart - 1);
            } else {
                role = -1;
            }
            break;
        case 1:
            if(this->currentMap[yStart][xStart - 1] == -1) {
                this->currentMap[yStart][xStart - 1] = role;
                this->currentMap[yStart][xStart] = -1;
                this->rolesInfo[role].setRoleInfoX(xStart - 1);
            } else {
                role = -1;
            }
            break;
        case 2:
            if(this->currentMap[yStart][xStart + 1] == -1) {
                this->currentMap[yStart][xStart + 1] = role;
                this->currentMap[yStart][xStart] = -1;
                this->rolesInfo[role].setRoleInfoX(xStart + 1);
            } else {
                role = -1;
            }
            break;
        case 3:
            if(this->currentMap[yStart + 1][xStart] == -1) {
                this->currentMap[yStart + 1][xStart] = role;
                this->currentMap[yStart][xStart] = -1;
                this->rolesInfo[role].setRoleInfoY(yStart + 1);
            } else {
                role = -1;
            }
            break;
        }
    }
}

void GameCore::resetAll()
{
    this->levelName.clear();
    for(int i = 0; i < 5; i++) {
        for(int j = 0; j < 4; j++) {
            this->currentMap[i][j] = -1;
        }
    }
    this->rolesInfo.clear();
    this->steps = 0;
}

void GameCore::changeSoundState(int &select)
{
    this->closeSound = !this->closeSound;
    if(this->closeSound) {
        this->myAudioPlayer->closeSound();
    } else {
        this->myAudioPlayer->resumeSound();
    }
    this->myGameGUI->showScene(this->rolesInfo, select, this->steps, this->closeSound);
}

bool GameCore::mouseClicked(bool &showHelp, int &x, int &y, int &select)
{
    if(showHelp) {
        if(x >= GameSystem::FIELD_LEFT + 250 && x <= GameSystem::FIELD_RIGHT + 24
                && y >= GameSystem::FIELD_TOP - 24 && y <= GameSystem::FIELD_TOP + 50) {
            showHelp = false;
            this->myGameGUI->showScene(this->rolesInfo, select, this->steps, this->closeSound);
        }
        return false;
    }

    /* 处理跳关 */
    if(y >= GameSystem::JUMP_TOP && y <= GameSystem::JUMP_BOTTOM) {
        if(x >= GameSystem::JUMP_BACK_L && x <= GameSystem::JUMP_BACK_R) {
            if(this->level > 1) {
                this->level--;
                resetAll();
                return true;
            }
        }
        if(x >= GameSystem::JUMP_FOREWORD_L && x <= GameSystem::JUMP_FOREWORD_R) {
            if(this->level < 10) {
                this->level++;
                resetAll();
                return true;
            }
        }
    }

    /* 处理移动 */
    if(x >= GameSystem::FIELD_LEFT && x <= GameSystem::FIELD_RIGHT &&
            y >= GameSystem::FIELD_TOP && y <= GameSystem::FIELD_BOTTOM) {
        int roleNum = isThereARole(x, y);
        if(roleNum != -1) {
            select = roleNum;
            this->myGameGUI->showScene(this->rolesInfo, select, this->steps, this->closeSound);
        } else if(select != -1) {
            controlMovement(select, x, y);
            if(select != -1) {
                this->steps++;
                this->myGameGUI->showScene(this->rolesInfo, select, this->steps, this->closeSound);
                if(!this->closeSound) {
                    this->myAudioPlayer->playSound("media/move.wav");
                }
                if(this->rolesInfo[0].getRoleInfoX() == 1 && this->rolesInfo[0].getRoleInfoY() == 3) {
                    this->level++;
                    resetAll();
                    return true;
                }
            } else {
                this->myGameGUI->showScene(this->rolesInfo, select, this->steps, this->closeSound);
            }
        } else {
        }
    }

    /* 处理重玩本关和声音 */
    if(y >= GameSystem::RESET_SOUND_TOP && y <= GameSystem::RESET_SOUND_BOTTOM) {
        if(x >= GameSystem::RESET_L && x <= GameSystem::RESET_R) {
            resetAll();
            return true;
        }
        if(x >= GameSystem::SOUND_L && x <= GameSystem::SOUND_R) {
            changeSoundState(select);
        }
    }

    /* 处理帮助 */
    if(x >= GameSystem::HELP_LEFT && x<= GameSystem::HELP_RIGHT
            && y>= GameSystem::HELP_TOP && y<= GameSystem::HELP_BOTTOM) {
        showHelp = true;
        this->myGameGUI->showHelp();
    }

    return false;
}

void GameCore::runGame()
{

    this->myAudioPlayer->playMusic("media/background.mp3");
    while(this->level < 11) {
        int x, y, selectRole = -1;
        bool endThisLevel = false;
        bool showHelp = false;

        loadMapFromFile(this->level);
        this->myGameGUI->initLevel(this->level, this->levelName);
        this->myGameGUI->showScene(this->rolesInfo, selectRole, this->steps, this->closeSound);

        SDL_Event userEvent;
        while(SDL_WaitEvent(&userEvent) && !endThisLevel) {
            switch(userEvent.type) {
            case SDL_QUIT:
                exit(1);
                break;
            case SDL_MOUSEBUTTONDOWN:
                x = userEvent.motion.x;
                y = userEvent.motion.y;
                endThisLevel = mouseClicked(showHelp, x, y, selectRole);
                break;
            case SDL_KEYDOWN:
                SDLKey sym = userEvent.key.keysym.sym;
                switch(sym) {
                case SDLK_n:
                    if(!showHelp) {
                        if(this->level < 10) {
                            this->level++;
                            resetAll();
                            endThisLevel = true;
                        }
                    }
                    break;
                case SDLK_b:
                    if(!showHelp) {
                        if(this->level > 1) {
                            this->level--;
                            resetAll();
                            endThisLevel = true;
                        }
                    }
                    break;
                case SDLK_r:
                    if(!showHelp) {
                        resetAll();
                        endThisLevel = true;
                    }
                    break;
                case SDLK_s:
                    changeSoundState(selectRole);
                    break;
                case SDLK_h:
                    this->myGameGUI->showHelp();
                    showHelp = true;
                    break;
                case SDLK_ESCAPE:
                    if(showHelp) {
                        showHelp = false;
                    }
                    this->myGameGUI->showScene(this->rolesInfo, selectRole, this->steps, this->closeSound);
                    break;
                case SDLK_q:
                    exit(0);
                default:
                    continue;
                }
            }
        }
    }
}
